package xyz.larkin.common.api.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import redis.clients.jedis.*;
import xyz.larkin.common.api.RedisService;
import xyz.larkin.common.enums.ConstantKey;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * Created by liujin on 2018/5/30.
 *
 * @description redis服务接口实现
 */
@Service(value = "redisService")
public class RedisServiceImpl implements RedisService, InitializingBean {

    private Logger logger = LoggerFactory.getLogger(RedisServiceImpl.class);
    private final static String logPrefix = "[RedisService]";
    @Value("${redis.cluster.nodes}")
    private String hostAndPorts;
    @Value("${redis.max.direction}")
    private Integer maxRedirections;
    @Value("${redis.command.timeout}")
    private Integer timeout;
    @Value("${redis.jedis.pool.max-active}")
    private Integer maxTotal;
    @Value("${redis.jedis.pool.max-wait}")
    private Integer maxWaitMillis;
    @Value("${redis.jedis.pool.max-idle}")
    private Integer maxIdle;
    @Value("${redis.jedis.pool.min-idle}")
    private Integer minIdle;

    private JedisCluster jedisCluster;

    @Override
    public boolean set(String key, String value,int seconds ) {
        String result = jedisCluster.setex(key, seconds, value);
        logger.debug("{}set key:{},value:{},result:{}", logPrefix, key, value, result);
        if(ConstantKey.OK.equals(result)) {
            return true;
        }
        return false;
    }

    @Override
    public String get(String key) {
        String value = jedisCluster.get(key);
        logger.debug(logPrefix + "get key:" + key +",value:"+ value);
        return value;
    }

    @Override
    public Long del(String key) {
        logger.debug(logPrefix+ "del key:" + key);
        return jedisCluster.del(key);
    }

    @Override
    public Long delAll(String pattern) throws Exception {
        //获取所有的jedis服务节点
        Long account = 0L;
        Map<String, JedisPool> clusters = jedisCluster.getClusterNodes();
        for(String node:clusters.keySet()) {
            JedisPool jedis = clusters.get(node);
            Jedis conn = jedis.getResource();
            Set<String> keys = conn.keys(pattern);
            keys.forEach((item)->{
                logger.debug(logPrefix + "del key:" + item);
                jedisCluster.del(item);
            });
            account += keys.size();
        }
        logger.info(logPrefix + "已经删除可以匹配:[" + pattern + "]的主键,共" + account + "个");
        return account;
    }

    @Override
    public Long addList(String key, String... value) {
        return jedisCluster.lpush(key, value);
    }

    @Override
    public List<String> getList(String key, int start, int end) {
        return jedisCluster.lrange(key, start, end);
    }

    @Override
    public Long removeList(String key, int times, String value) {
        return jedisCluster.lrem(key, times, value);
    }

    @Override
    public String removeList(String key, int start, int end) {
        return jedisCluster.ltrim(key, start, end);
    }

    @Override
    public List<String> sortList(String key, boolean isDesc) {
        SortingParams params = new SortingParams();
        if(isDesc) {
            params.desc();  // 降序
        }
        return jedisCluster.sort(key, params);
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        //创建jedisNode 初始化jedisCluster
        if(StringUtils.isEmpty(hostAndPorts)) {
            logger.error("redis host is empty!");
            throw new IllegalArgumentException("redis host is empty");
        }
        Set<HostAndPort> haps = parseHostAndPort(hostAndPorts);
        if(haps==null || haps.size()<= 0) {
            logger.error("no redis host is enable!");
            throw new IllegalArgumentException("no redis host is enable");
        }
        jedisCluster = new JedisCluster(haps, timeout, maxRedirections, getPoolConfig());
    }

    public JedisPoolConfig getPoolConfig() {

        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(maxTotal);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIdle);
        return jedisPoolConfig;
    }

    private Set<HostAndPort> parseHostAndPort(String hostAndPorts) {
        Pattern hostPattern = Pattern.compile("^.+[:]\\d{1,5}\\s*$");
        Set<HostAndPort> hapsSet = new HashSet<>();
        String[] hosts = hostAndPorts.split(",");
        for(String host : hosts) {
            if(!hostPattern.matcher(host).matches()) {
                return null;
            }
            String[] hostPort = host.split(":");
            if(hostPort.length !=2) {
                return null;
            }
            HostAndPort hostAndPort = new HostAndPort(hostPort[0], Integer.valueOf(hostPort[1]));
            hapsSet.add(hostAndPort);
        }
        return hapsSet;
    }
}